package sip

import (
	"fmt"
	"log"
	"regexp"
	"strconv"
	"strings"

	"gitee.com/larry_wan/go-lib/utils"
)

type Response struct {
	Version    string
	StatusCode int
	Status     string
	Headers    []string
	HeaderMap  map[string]string
	Header     string
	Body       string
}

func UnmarshalResponse(header, body string) (res *Response, err error) {
	lines := strings.Split(strings.TrimSpace(header), "\r\n")
	if len(lines) == 0 {
		err = fmt.Errorf("response with 0 lines header")
		return
	}
	items := regexp.MustCompile("\\s+").Split(strings.TrimSpace(lines[0]), 3)
	if len(items) < 2 {
		err = fmt.Errorf("response status line incorrect")
		return
	}
	code, _ := strconv.Atoi(items[1])
	status := ""
	if len(items) >= 3 {
		status = items[2]
	}
	headers := make([]string, 0)
	headerMap := make(map[string]string)
	for i := 1; i < len(lines); i++ {
		line := strings.TrimSpace(lines[i])
		headerItems := regexp.MustCompile(":\\s+").Split(line, 2)
		if len(headerItems) < 2 {
			continue
		}
		headers = append(headers, headerItems[0])
		headerMap[headerItems[0]] = headerItems[1]
	}
	res = &Response{
		Version:    items[0],
		StatusCode: code,
		Status:     status,
		Headers:    headers,
		HeaderMap:  headerMap,
		Header:     header,
		Body:       body,
	}
	return
}

func (res *Response) String() string {
	str := fmt.Sprintf("%s %d %s\r\n", res.Version, res.StatusCode, res.Status)
	for _, key := range res.Headers {
		str += fmt.Sprintf("%s: %s\r\n", key, res.HeaderMap[key])
	}
	str += "\r\n"
	str += res.Body
	return str
}

func (res *Response) SetBody(body string) *Response {
	res.Body = body
	res.SetHeader("Content-Length", fmt.Sprintf("%d", len(body)))
	return res
}

// Challenge 质询
func (res *Response) Challenge(realm string, contact string) *Response {
	res.StatusCode = 401
	res.Status = "Unauthorized"
	nonce := utils.MD5(utils.ShortID())
	res.SetHeader("Contact", contact)
	res.SetHeader("User-Agent", "ZTRSGBS")
	//res.SetHeader("WWW-Authenticate", fmt.Sprintf(`Digest realm="%s",qop="auth",nonce="%s"`, realm, nonce))
	res.SetHeader("WWW-Authenticate", fmt.Sprintf(`Digest realm="%s",nonce="%s"`, realm, nonce))

	return res
}

func (res *Response) Forbidden() *Response {
	res.StatusCode = 403
	res.Status = "Forbidden"
	return res
}

func (res *Response) EnsureToTag() *Response {
	reg := regexp.MustCompile(`(?Us);tag=.*$`)
	if !reg.MatchString(res.HeaderMap["To"]) {
		res.HeaderMap["To"] = res.HeaderMap["To"] + ";tag=" + GenTag()
	}
	return res
}

func (res *Response) SetHeader(key, value string) *Response {
	if _, ok := res.HeaderMap[key]; !ok {
		res.Headers = append(res.Headers, key)
	}
	res.HeaderMap[key] = value
	return res
}

func (res *Response) RemoveHeader(key string) *Response {
	delete(res.HeaderMap, key)
	for i := 0; i < len(res.Headers); i++ {
		if res.Headers[i] == key {
			res.Headers = append(res.Headers[:i], res.Headers[i+1:]...)
			i--
		}
	}
	return res
}

func (res *Response) GetContentLength() (length int) {
	length = len(res.Body)
	return
}

func (res *Response) SendByTransport(transport *Transport) (err error) {
	defer func() {
		if err != nil {
			log.Println(err)
		}
	}()
	resText := res.String()
	resBytes := []byte(resText)
	resLen := len(resBytes)
	n, e := transport.Write(resBytes)
	if e != nil {
		err = fmt.Errorf("response send failed, %v", e)
		return
	}
	if n != resLen {
		err = fmt.Errorf("response send failed, send not complete")
		return
	}
	//Logf("回复：[%s]>>>>>>[%s:%d]\r\n%v", transport.UDPConn.LocalAddr().String(), transport.RemoteIP, transport.RemotePort, res)
	if transport.Protocol=="UDP" {
		Logf("回复[UDP]：[%s]>>>>>>[%s:%d]\r\n%v", transport.UDPConn.LocalAddr().String(), transport.RemoteIP, transport.RemotePort, res)	 
	} else {
		Logf("回复[TCP]：[%s]>>>>>>[%s:%d]\r\n%v", transport.TCPConn.LocalAddr().String(), transport.RemoteIP, transport.RemotePort, res)

	}
	return
}

func (res *Response) NewSession() *Session {
	return &Session{
		CallID: res.HeaderMap["Call-ID"],
		From:   res.HeaderMap["From"],
		To:     res.HeaderMap["To"],

		KV: make(map[string]interface{}),
	}
}
